package club_controller

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"shimmer/neusoft_club_backend/controllers/club_controller/application"
	"shimmer/neusoft_club_backend/controllers/club_controller/department"
	"shimmer/neusoft_club_backend/controllers/club_controller/form"
	"shimmer/neusoft_club_backend/controllers/club_controller/invite"
	"shimmer/neusoft_club_backend/controllers/club_controller/page"
	"shimmer/neusoft_club_backend/controllers/club_controller/position"
	"shimmer/neusoft_club_backend/controllers/cons"
	"shimmer/neusoft_club_backend/controllers/utils"
	"shimmer/neusoft_club_backend/dao/domain"
	"shimmer/neusoft_club_backend/middlewares/auth_middleware"
	"shimmer/neusoft_club_backend/services"
	"shimmer/neusoft_club_backend/services/club_service"
	"shimmer/neusoft_club_backend/services/errs"
	"shimmer/neusoft_club_backend/services/user_service"
)

// @Summary 查询某个社团
// @Description
// @Tags 社团
// @Param clubID path integer true "社团ID"
// @Success 200 {object} []domain.ClubDTO
// @Router /api/club/{clubID} [get]
func getClub(c *gin.Context) {
	_, err := domain.GetUserFromContext(c)
	inner := err == nil
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	clubBinding := &cons.ClubUriParamBinding{}
	if err := c.ShouldBindUri(clubBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	where := map[string]interface{}{
		"clubs.id": clubBinding.ClubID,
	}
	if !inner {
		where["clubs.outer_visible"] = true
	}
	res, err := club_service.FindClub(where)
	if err != nil {
		services.AbortWithError(c, err)
	}
	c.JSON(http.StatusOK, res)
}

// @Summary 获取所有的社团
// @Description
// @Tags 社团
// @Param page query integer false "页面"
// @Param size query integer true "页面大小"
// @Success 200 {object} []domain.ClubDTO
// @Router /api/club [get]
func getAllClubs(c *gin.Context) {
	_, err := domain.GetUserFromContext(c)
	inner := err == nil
	pageQuery, err := utils.GetPaginationFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	where := map[string]interface{}{}
	if !inner {
		where["outer_visible"] = true
	}
	clubs, err := club_service.GetAllClubs(where, pageQuery)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.JSON(http.StatusOK, clubs)
}

type getAllClubsReq struct {
	Where *map[string]interface{} `json:"where" xml:"where" form:"where" uri:"where" binding:"-"`
}

// @Summary 社团搜索
// @Description 没做
// @Tags 社团
// @Param page query integer false "页面"
// @Param size query integer true "页面大小"
// @Param param body club_controller.getAllClubsReq false "查询"
// @Success 200 {object} []domain.ClubDTO
// @Router /api/club/search [post]
func searchClubs(c *gin.Context) {
	_, err := domain.GetUserFromContext(c)
	inner := err == nil
	pageQuery, err := utils.GetPaginationFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	req := &getAllClubsReq{}
	if err = c.ShouldBindJSON(req); err != nil {
		services.AbortWithError(c, err)
		return
	}
	where := map[string]interface{}{}
	if req.Where != nil {
		where = *req.Where
	}
	delete(where, "outer_visible")

	if !inner {
		where["outer_visible"] = true
	}
	clubs, err := club_service.GetAllClubs(where, pageQuery)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.JSON(http.StatusOK, clubs)
}

// @Summary 更新社团信息
// @Description
// @Tags 社团
// @Param clubID path integer true "社团ID"
// @Param value body club_service.UpdateClubReq true "社团信息"
// @Success 200 {object} domain.ClubDTO
// @Router /api/club/{clubID} [put]
func updateClubInfo(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	isAdmin, err := club_service.CheckIsAdmin(user.ID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if !isAdmin {
		services.AbortWithError(c, errs.ErrNotAdmin)
		return
	}
	req := &club_service.UpdateClubReq{}
	if err = c.ShouldBind(req); err != nil {
		services.AbortWithError(c, err)
		return
	}
	clubBinding := &cons.ClubUriParamBinding{}
	if err = c.ShouldBindUri(clubBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	res, err := club_service.UpdateClub(map[string]interface{}{
		"id": clubBinding.ClubID,
	}, *req)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.JSON(http.StatusOK, res)
}

// @Summary 删除社团
// @Description
// @Tags 社团
// @Param clubID path integer true "社团ID"
// @Success 204
// @Router /api/club/{clubID} [delete]
func deleteClub(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	isAdmin, err := club_service.CheckIsAdmin(user.ID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if !isAdmin {
		services.AbortWithError(c, errs.ErrNotAdmin)
		return
	}
	clubBinding := &cons.ClubUriParamBinding{}
	if err = c.ShouldBindUri(clubBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	err = club_service.DeleteClub(map[string]interface{}{
		"id": clubBinding.ClubID,
	})
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.AbortWithStatus(http.StatusNoContent)
}

// @Summary 创建社团
// @Description
// @Tags 社团
// @Param value body club_service.CreateClubReq true "创建必填"
// @Success 200 {object} domain.ClubDTO
// @Router /api/club [post]
func createClub(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	isAdmin, err := club_service.CheckIsAdmin(user.ID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if !isAdmin {
		services.AbortWithError(c, errs.ErrNotAdmin)
		return
	}
	value := &club_service.CreateClubReq{}

	if err = c.ShouldBind(value); err != nil {
		services.AbortWithError(c, err)
		return
	}
	res, err := club_service.CreateClub(*value)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.JSON(http.StatusOK, res)

}

type addLeaderToClubReq struct {
	UserID int64 `json:"user_id" form:"user_id" xml:"user_id" binding:"required"`
}

// @Summary 为社团添加一个社长
// @Description
// @Tags 社团
// @Param clubID path integer true "社团ID"
// @Param value body club_controller.addLeaderToClubReq true "参数"
// @Success 204
// @Router /api/club/{clubID}/leader [post]
func addLeaderToClub(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	isAdmin, err := club_service.CheckIsAdmin(user.ID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if !isAdmin {
		services.AbortWithError(c, errs.ErrNotAdmin)
		return
	}
	req := &addLeaderToClubReq{}
	if err = c.ShouldBind(req); err != nil {
		services.AbortWithError(c, err)
		return
	}
	clubBinding := &cons.ClubUriParamBinding{}
	if err = c.ShouldBindUri(clubBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	inClub, err := club_service.CheckInClub(user.ID, clubBinding.ClubID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if !inClub {
		services.AbortWithError(c, errs.ErrIsNotClubMember)
		return
	}
	targetUser, err := user_service.FindUserByID(req.UserID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if err = club_service.AddLeaderToClub(targetUser, clubBinding.ClubID); err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.AbortWithStatus(http.StatusNoContent)
}

type removeLeaderFromClubReq struct {
	UserID int64 `json:"user_id" xml:"user_id" form:"user_id" xml:"user_id" binding:"required"`
}

// @Summary 从社团中移除一个社长
// @Description
// @Tags 社团
// @Param clubID path integer true "社团ID"
// @Param value body club_controller.removeLeaderFromClubReq true "参数"
// @Success 204
// @Router /api/clubs/{clubID}/leader [delete]
func removeLeaderFromClub(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	isAdmin, err := club_service.CheckIsAdmin(user.ID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if !isAdmin {
		services.AbortWithError(c, errs.ErrNotAdmin)
		return
	}
	req := &removeLeaderFromClubReq{}
	if err = c.ShouldBind(req); err != nil {
		services.AbortWithError(c, err)
		return
	}
	clubBinding := &cons.ClubUriParamBinding{}
	if err = c.ShouldBindUri(clubBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	targetUser, err := user_service.FindUserByID(req.UserID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if err = club_service.RemoveLeaderFromClub(targetUser, clubBinding.ClubID); err != nil {
		services.AbortWithError(c, err)
		return
	}

	c.AbortWithStatus(http.StatusNoContent)

}

func ConfigureClubController(r *gin.RouterGroup) {
	{
		departmentGroup := r.Group(fmt.Sprintf("/:%s/department", cons.ClubUriParam))
		department.ConfigureClubDepartmentController(departmentGroup)
	}
	{
		formGroup := r.Group(fmt.Sprintf("/:%s/form", cons.ClubUriParam))
		form.ConfigureClubFormController(formGroup)
	}
	{
		inviteGroup := r.Group(fmt.Sprintf("/:%s/invite", cons.ClubUriParam))
		invite.ConfigureClubInviteController(inviteGroup)
	}
	{
		pageGroup := r.Group(fmt.Sprintf("/:%s/page", cons.ClubUriParam))
		page.ConfigureClubPageController(pageGroup)
	}
	{
		applicationGroup := r.Group(fmt.Sprintf("/:%s/application", cons.ClubUriParam))
		application.ConfigureClubUserApplicationController(applicationGroup)
	}
	{
		positionGroup := r.Group(fmt.Sprintf("/:%s/position", cons.ClubUriParam), auth_middleware.AuthLoginMiddleware())
		position.ConfigureClubPositionController(positionGroup)
	}
	r.GET("/", auth_middleware.AuthUserMiddleware(false), getAllClubs)
	r.POST("/", auth_middleware.AuthLoginMiddleware(), createClub)
	r.POST("/search", auth_middleware.AuthUserMiddleware(false), searchClubs)
	r.GET(fmt.Sprintf("/:%s", cons.ClubUriParam), auth_middleware.AuthLoginMiddleware(), getClub)
	r.PUT(fmt.Sprintf("/:%s", cons.ClubUriParam), auth_middleware.AuthLoginMiddleware(), updateClubInfo)
	r.DELETE(fmt.Sprintf("/:%s", cons.ClubUriParam), auth_middleware.AuthLoginMiddleware(), deleteClub)
	r.POST(fmt.Sprintf("/:%s/leader", cons.ClubUriParam), auth_middleware.AuthLoginMiddleware(), addLeaderToClub)
	r.DELETE(fmt.Sprintf("/:%s/leader", cons.ClubUriParam), auth_middleware.AuthLoginMiddleware(), removeLeaderFromClub)
}
